package com.silverhaze.diamond.common.util;

import com.silverhaze.diamond.common.constants.DiamondConstants;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;

/**
 * User: Babanin
 * Date: 28.04.2008
 * Time: 9:25:41
 */
public class ServiceLocator {
    public static final String LOCAL_ADDRESS = "localhost";
//    public static final String LOCAL_ADDRESS = "192.168.0.101";
//    public static final String LOCAL_ADDRESS = "10.10.0.91";


    private static InitialContext ctx;
    private static boolean JWSMode = false;

    private static Map<Class, Object> serviceCache = new HashMap<Class, Object>();

    public static <T> T localLookup(Class<T> clazz) {
        return clazz.cast(lookup(getJNDIName(clazz, true)));
    }

    public static <T> T localFind(Class<T> clazz) {
        Object o = find(getJNDIName(clazz, true));

        if (o != null) {
            return clazz.cast(o);
        } else {
            return null;
        }
    }

    public static <T> T remoteLookup(Class<T> clazz) {
        Object service = serviceCache.get(clazz);

        if (service == null) {
            service = lookup(getJNDIName(clazz, false));
            serviceCache.put(clazz, service);
        }

        return clazz.cast(service);
    }

    public static <T> T remoteLookup(Class<T> clazz, String name) {
        Object service = serviceCache.get(clazz);

        if (service == null) {
            String jndiName = getJNDIName(name, false);
            System.out.println("Lookup: " + jndiName);

            service = lookup(jndiName);
            serviceCache.put(clazz, service);
        }

        return clazz.cast(service);
    }

    public static <T> T remoteFind(Class<T> clazz) {
        Object o = find(getJNDIName(clazz, false));

        if (o != null) {
            return clazz.cast(o);
        } else {
            return null;
        }
    }

    public static <T> T lookup(Class<T> clazz) {
        try {
            return localLookup(clazz);
        } catch (Exception e) {
            try {
                return remoteLookup(clazz);
            } catch (Exception subException) {
                throw new RuntimeException(subException);
            }
        }
    }

    private static String getJNDIName(String name, boolean local) {
        return name + (local ? "/local" : "/remote");
    }

    private static String getJNDIName(Class clazz, boolean local) {
        return DiamondConstants.JNDI_DOMAIN + getJNDIName(clazz.getSimpleName(), local);
    }

    public static Object lookup(String jndi) {
        try {
            return getInitialContext().lookup(jndi);
        } catch (NamingException e) {
            throw new RuntimeException(e);
        }
    }

    public static Object find(String jndi) {
        try {
            return getInitialContext().lookup(jndi);
        } catch (NamingException e) {
            return null;
        }
    }

    public static InitialContext getInitialContext() {
        try {
            if (ctx == null) {
                Hashtable<String, String> props = new Hashtable<String, String>();
                props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
                props.put(Context.PROVIDER_URL, getHost() + ":1099");

                ctx = new InitialContext(props);
            }

            return ctx;
        } catch (NamingException e) {
            throw new RuntimeException("Can't create InititalContext", e);
        }
    }

    private static String getHost() {
        Properties properties = new Properties();
        String jbossBind = System.getProperty("jboss.bind.address", null);

        if (jbossBind != null) {
            return jbossBind;
        }

        try {
            properties.load(new FileReader("server.properties"));
            return properties.getProperty("server-client");
        } catch (IOException e) {
            e.printStackTrace();
        }

        throw new IllegalStateException("Отсутсвует файл с настройками (server.properties)");
    }

    public static void enableJWSMode() {
        JWSMode = true;
    }

    public static boolean isJWSMode() {
        return JWSMode;
    }
}